/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.util;

import com.aduib.boot.common.exception.CommonException;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

/**
 * @description: ArrayUtils
 * @author: zzh
 * @date: 2021/10/27 16:56
 */
public class ArrayUtils {

  public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];

  /** 数组中元素未找到的下标，值为-1 */
  public static final int INDEX_NOT_FOUND = -1;
  /**
   * 数组是否为非空
   *
   * @param <T> 数组元素类型
   * @param array 数组
   * @return 是否为非空
   */
  public static <T> boolean isNotEmpty(T[] array) {
    return (array != null && array.length != 0);
  }

  /**
   * 数组中是否包含元素
   *
   * @param <T> 数组元素类型
   * @param array 数组
   * @param value 被检查的元素
   * @return 是否包含
   */
  public static <T> boolean contains(T[] array, T value) {
    return indexOf(array, value) > INDEX_NOT_FOUND;
  }

  /**
   * @param array
   * @param value
   * @return
   */
  public static boolean contains(char[] array, char value) {
    return indexOf(array, value) > INDEX_NOT_FOUND;
  }

  /**
   * 数组是否为空<br>
   * 此方法会匹配单一对象，如果此对象为{@code null}则返回true<br>
   * 如果此对象为非数组，理解为此对象为数组的第一个元素，则返回false<br>
   * 如果此对象为数组对象，数组长度大于0情况下返回false，否则返回true
   *
   * @param array 数组
   * @return 是否为空
   */
  public static boolean isEmpty(Object array) {
    if (array != null) {
      if (isArray(array)) {
        return 0 == Array.getLength(array);
      }
      return false;
    }
    return true;
  }

  /**
   * 返回数组中指定元素所在位置，未找到返回{@link #INDEX_NOT_FOUND}
   *
   * @param <T> 数组类型
   * @param array 数组
   * @param value 被检查的元素
   * @return 数组中指定元素所在位置，未找到返回{@link #INDEX_NOT_FOUND}
   */
  public static <T> int indexOf(T[] array, Object value) {
    if (null != array) {
      for (int i = 0; i < array.length; i++) {
        if (ObjectUtils.equal(value, array[i])) {
          return i;
        }
      }
    }
    return INDEX_NOT_FOUND;
  }

  /**
   * 返回数组中指定元素所在位置，未找到返回{@link #INDEX_NOT_FOUND}
   *
   * @param array 数组
   * @param value 被检查的元素
   * @return 数组中指定元素所在位置，未找到返回{@link #INDEX_NOT_FOUND}
   */
  public static int indexOf(char[] array, char value) {
    if (null != array) {
      for (int i = 0; i < array.length; i++) {
        if (value == array[i]) {
          return i;
        }
      }
    }
    return INDEX_NOT_FOUND;
  }

  /**
   * 对象是否为数组对象
   *
   * @param obj 对象
   * @return 是否为数组对象，如果为{@code null} 返回false
   */
  public static boolean isArray(Object obj) {
    if (null == obj) {
      // throw new NullPointerException("Object check for isArray is null");
      return false;
    }
    return obj.getClass().isArray();
  }

  /**
   * 数组或集合转String
   *
   * @param obj 集合或数组对象
   * @return 数组字符串，与集合转字符串格式相同
   */
  public static String toString(Object obj) {
    if (null == obj) {
      return null;
    }

    if (obj instanceof long[]) {
      return Arrays.toString((long[]) obj);
    } else if (obj instanceof int[]) {
      return Arrays.toString((int[]) obj);
    } else if (obj instanceof short[]) {
      return Arrays.toString((short[]) obj);
    } else if (obj instanceof char[]) {
      return Arrays.toString((char[]) obj);
    } else if (obj instanceof byte[]) {
      return Arrays.toString((byte[]) obj);
    } else if (obj instanceof boolean[]) {
      return Arrays.toString((boolean[]) obj);
    } else if (obj instanceof float[]) {
      return Arrays.toString((float[]) obj);
    } else if (obj instanceof double[]) {
      return Arrays.toString((double[]) obj);
    } else if (ArrayUtils.isArray(obj)) {
      // 对象数组
      try {
        return Arrays.deepToString((Object[]) obj);
      } catch (Exception ignore) {
        // ignore
      }
    }

    return obj.toString();
  }

  /**
   * 获取数组长度<br>
   * 如果参数为{@code null}，返回0
   *
   * <pre>
   * ArrayUtils.length(null)            = 0
   * ArrayUtils.length([])              = 0
   * ArrayUtils.length([null])          = 1
   * ArrayUtils.length([true, false])   = 2
   * ArrayUtils.length([1, 2, 3])       = 3
   * ArrayUtils.length(["a", "b", "c"]) = 3
   * </pre>
   *
   * @param array 数组对象
   * @return 数组长度
   * @throws IllegalArgumentException 如果参数不为数组，抛出此异常
   * @see Array#getLength(Object)
   */
  public static int length(Object array) throws IllegalArgumentException {
    if (null == array) {
      return 0;
    }
    return Array.getLength(array);
  }

  /**
   * 获取数组对象中指定index的值，支持负数，例如-1表示倒数第一个值<br>
   * 如果数组下标越界，返回null
   *
   * @param <T> 数组元素类型
   * @param array 数组对象
   * @param index 下标，支持负数
   * @return 值
   */
  @SuppressWarnings("unchecked")
  public static <T> T get(Object array, int index) {
    if (null == array) {
      return null;
    }

    if (index < 0) {
      index += Array.getLength(array);
    }
    try {
      return (T) Array.get(array, index);
    } catch (ArrayIndexOutOfBoundsException e) {
      return null;
    }
  }

  /**
   * 新建一个空数组
   *
   * @param <T> 数组元素类型
   * @param componentType 元素类型
   * @param newSize 大小
   * @return 空数组
   */
  @SuppressWarnings("unchecked")
  public static <T> T[] newArray(Class<?> componentType, int newSize) {
    return (T[]) Array.newInstance(componentType, newSize);
  }

  /**
   * 新建一个空数组
   *
   * @param newSize 大小
   * @return 空数组
   */
  public static Object[] newArray(int newSize) {
    return new Object[newSize];
  }

  // ---------------------------------------------------------------------- range

  /**
   * 生成一个从0开始的数字列表<br>
   *
   * @param excludedEnd 结束的数字（不包含）
   * @return 数字列表
   */
  public static int[] range(int excludedEnd) {
    return range(0, excludedEnd, 1);
  }

  /**
   * 生成一个数字列表<br>
   * 自动判定正序反序
   *
   * @param includedStart 开始的数字（包含）
   * @param excludedEnd 结束的数字（不包含）
   * @return 数字列表
   */
  public static int[] range(int includedStart, int excludedEnd) {
    return range(includedStart, excludedEnd, 1);
  }

  /**
   * 生成一个数字列表<br>
   * 自动判定正序反序
   *
   * @param includedStart 开始的数字（包含）
   * @param excludedEnd 结束的数字（不包含）
   * @param step 步进
   * @return 数字列表
   */
  public static int[] range(int includedStart, int excludedEnd, int step) {
    if (includedStart > excludedEnd) {
      int tmp = includedStart;
      includedStart = excludedEnd;
      excludedEnd = tmp;
    }

    if (step <= 0) {
      step = 1;
    }

    int deviation = excludedEnd - includedStart;
    int length = deviation / step;
    if (deviation % step != 0) {
      length += 1;
    }
    int[] range = new int[length];
    for (int i = 0; i < length; i++) {
      range[i] = includedStart;
      includedStart += step;
    }
    return range;
  }

  /**
   * 交换数组中两个位置的值
   *
   * @param <T> 元素类型
   * @param array 数组
   * @param index1 位置1
   * @param index2 位置2
   * @return 交换后的数组，与传入数组为同一对象
   */
  public static <T> T[] swap(T[] array, int index1, int index2) {
    if (isEmpty(array)) {
      throw new IllegalArgumentException("Array must not empty !");
    }
    T tmp = array[index1];
    array[index1] = array[index2];
    array[index2] = tmp;
    return array;
  }

  /**
   * 交换数组中两个位置的值
   *
   * @param array 数组对象
   * @param index1 位置1
   * @param index2 位置2
   * @return 交换后的数组，与传入数组为同一对象
   */
  public static Object swap(Object array, int index1, int index2) {
    if (isEmpty(array)) {
      throw new IllegalArgumentException("Array must not empty !");
    }
    Object tmp = get(array, index1);
    Array.set(array, index1, Array.get(array, index2));
    Array.set(array, index2, tmp);
    return array;
  }

  // ------------------------------------------------------------------- sub

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static byte[] sub(byte[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new byte[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new byte[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static int[] sub(int[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new int[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new int[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static long[] sub(long[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new long[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new long[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static short[] sub(short[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new short[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new short[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static char[] sub(char[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new char[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new char[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static double[] sub(double[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new double[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new double[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static float[] sub(float[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new float[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new float[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static boolean[] sub(boolean[] array, int start, int end) {
    int length = Array.getLength(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new boolean[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new boolean[0];
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param <T> 数组元素类型
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   * @see Arrays#copyOfRange(Object[], int, int)
   */
  public static <T> T[] sub(T[] array, int start, int end) {
    int length = length(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return newArray(array.getClass().getComponentType(), 0);
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return newArray(array.getClass().getComponentType(), 0);
      }
      end = length;
    }
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @return 新的数组
   */
  public static Object[] sub(Object array, int start, int end) {
    return sub(array, start, end, 1);
  }

  /**
   * 获取子数组
   *
   * @param array 数组
   * @param start 开始位置（包括）
   * @param end 结束位置（不包括）
   * @param step 步进
   * @return 新的数组
   */
  public static Object[] sub(Object array, int start, int end, int step) {
    int length = length(array);
    if (start < 0) {
      start += length;
    }
    if (end < 0) {
      end += length;
    }
    if (start == length) {
      return new Object[0];
    }
    if (start > end) {
      int tmp = start;
      start = end;
      end = tmp;
    }
    if (end > length) {
      if (start >= length) {
        return new Object[0];
      }
      end = length;
    }

    if (step <= 1) {
      step = 1;
    }

    final ArrayList<Object> list = new ArrayList<>();
    for (int i = start; i < end; i += step) {
      list.add(get(array, i));
    }

    return list.toArray();
  }

  /**
   * 将新元素添加到已有数组中<br>
   * 添加新元素会生成一个新的数组，不影响原数组
   *
   * @param <T>         数组元素类型
   * @param buffer      已有数组
   * @param newElements 新元素
   * @return 新数组
   */
  @SafeVarargs
  public static <T> T[] append(T[] buffer, T... newElements) {
    if (isEmpty(buffer)) {
      return newElements;
    }
    return insert(buffer, buffer.length, newElements);
  }

  /**
   * 将新元素添加到已有数组中<br>
   * 添加新元素会生成一个新的数组，不影响原数组
   *
   * @param <T>         数组元素类型
   * @param array       已有数组
   * @param newElements 新元素
   * @return 新数组
   */
  @SafeVarargs
  public static <T> Object append(Object array, T... newElements) {
    if (isEmpty(array)) {
      return newElements;
    }
    return insert(array, length(array), newElements);
  }

  /**
   * 将新元素插入到到已有数组中的某个位置<br>
   * 添加新元素会生成一个新的数组，不影响原数组<br>
   * 如果插入位置为为负数，从原数组从后向前计数，若大于原数组长度，则空白处用null填充
   *
   * @param <T>         数组元素类型
   * @param buffer      已有数组
   * @param index       插入位置，此位置为对应此位置元素之前的空档
   * @param newElements 新元素
   * @return 新数组
   */
  @SuppressWarnings("unchecked")
  public static <T> T[] insert(T[] buffer, int index, T... newElements) {
    return (T[]) insert((Object) buffer, index, newElements);
  }

  /**
   * 将新元素插入到到已有数组中的某个位置<br>
   * 添加新元素会生成一个新的数组，不影响原数组<br>
   * 如果插入位置为为负数，从原数组从后向前计数，若大于原数组长度，则空白处用null填充
   *
   * @param <T>         数组元素类型
   * @param array       已有数组
   * @param index       插入位置，此位置为对应此位置元素之前的空档
   * @param newElements 新元素
   * @return 新数组
   */
  @SuppressWarnings({"unchecked", "SuspiciousSystemArraycopy"})
  public static <T> Object insert(Object array, int index, T... newElements) {
    if (isEmpty(newElements)) {
      return array;
    }
    if (isEmpty(array)) {
      return newElements;
    }

    final int len = length(array);
    if (index < 0) {
      index = (index % len) + len;
    }

    final T[] result = newArray(array.getClass().getComponentType(), Math.max(len, index) + newElements.length);
    System.arraycopy(array, 0, result, 0, Math.min(len, index));
    System.arraycopy(newElements, 0, result, index, newElements.length);
    if (index < len) {
      System.arraycopy(array, index, result, index + newElements.length, len - index);
    }
    return result;
  }


  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param array       数组
   * @param conjunction 分隔符
   * @return 连接后的字符串
   */
  public static String join(int[] array, CharSequence conjunction) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (int item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      sb.append(item);
    }
    return sb.toString();
  }

  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param array       数组
   * @param conjunction 分隔符
   * @return 连接后的字符串
   */
  public static String join(short[] array, CharSequence conjunction) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (short item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      sb.append(item);
    }
    return sb.toString();
  }

  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param array       数组
   * @param conjunction 分隔符
   * @return 连接后的字符串
   */
  public static String join(char[] array, CharSequence conjunction) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (char item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      sb.append(item);
    }
    return sb.toString();
  }

  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param array       数组
   * @param conjunction 分隔符
   * @return 连接后的字符串
   */
  public static String join(byte[] array, CharSequence conjunction) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (byte item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      sb.append(item);
    }
    return sb.toString();
  }

  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param array       数组
   * @param conjunction 分隔符
   * @return 连接后的字符串
   */
  public static String join(boolean[] array, CharSequence conjunction) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (boolean item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      sb.append(item);
    }
    return sb.toString();
  }

  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param array       数组
   * @param conjunction 分隔符
   * @return 连接后的字符串
   */
  public static String join(float[] array, CharSequence conjunction) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (float item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      sb.append(item);
    }
    return sb.toString();
  }

  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param array       数组
   * @param conjunction 分隔符
   * @return 连接后的字符串
   */
  public static String join(double[] array, CharSequence conjunction) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (double item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      sb.append(item);
    }
    return sb.toString();
  }



  /**
   * 以 conjunction 为分隔符将数组转换为字符串
   *
   * @param <T>         被处理的集合
   * @param array       数组
   * @param conjunction 分隔符
   * @param prefix      每个元素添加的前缀，null表示不添加
   * @param suffix      每个元素添加的后缀，null表示不添加
   * @return 连接后的字符串
   */
  public static <T> String join(T[] array, CharSequence conjunction, String prefix, String suffix) {
    if (null == array) {
      return null;
    }

    final StringBuilder sb = new StringBuilder();
    boolean isFirst = true;
    for (T item : array) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append(conjunction);
      }
      if (ArrayUtils.isArray(item)) {
        sb.append(join(ArrayUtils.wrap(item), conjunction, prefix, suffix));
      } else if (item instanceof Iterable<?>) {
        sb.append(CollectionUtils.join((Iterable<?>) item, conjunction, prefix, suffix));
      } else if (item instanceof Iterator<?>) {
        sb.append(CollectionUtils.join((Iterator<?>) item, conjunction, prefix, suffix));
      } else {
        sb.append(StrUtils.wrap(StrUtils.toString(item), prefix, suffix));
      }
    }
    return sb.toString();
  }




  /**
   * 包装数组对象
   *
   * @param obj 对象，可以是对象数组或者基本类型数组
   * @return 包装类型数组或对象数组
   * @throws  CommonException 对象为非数组
   */
  public static Object[] wrap(Object obj) {
    if (null == obj) {
      return null;
    }
    if (isArray(obj)) {
      try {
        return (Object[]) obj;
      } catch (Exception e) {
        final String className = obj.getClass().getComponentType().getName();
        switch (className) {
          case "long":
            return wrap((long[]) obj);
          case "int":
            return wrap((int[]) obj);
          case "short":
            return wrap((short[]) obj);
          case "char":
            return wrap((char[]) obj);
          case "byte":
            return wrap((byte[]) obj);
          case "boolean":
            return wrap((boolean[]) obj);
          case "float":
            return wrap((float[]) obj);
          case "double":
            return wrap((double[]) obj);
          default:
            throw new CommonException(e);
        }
      }
    }
    throw new CommonException(StrUtils.format("[{}] is not Array!", obj.getClass()));
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Integer[] wrap(int... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Integer[0];
    }

    final Integer[] array = new Integer[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组，null转为0
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static int[] unWrap(Integer... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new int[0];
    }

    final int[] array = new int[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], 0);
    }
    return array;
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Long[] wrap(long... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Long[0];
    }

    final Long[] array = new Long[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static long[] unWrap(Long... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new long[0];
    }

    final long[] array = new long[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], 0L);
    }
    return array;
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Character[] wrap(char... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Character[0];
    }

    final Character[] array = new Character[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static char[] unWrap(Character... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new char[0];
    }

    char[] array = new char[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], Character.MIN_VALUE);
    }
    return array;
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Byte[] wrap(byte... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Byte[0];
    }

    final Byte[] array = new Byte[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static byte[] unWrap(Byte... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new byte[0];
    }

    final byte[] array = new byte[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], (byte) 0);
    }
    return array;
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Short[] wrap(short... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Short[0];
    }

    final Short[] array = new Short[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static short[] unWrap(Short... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new short[0];
    }

    final short[] array = new short[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], (short) 0);
    }
    return array;
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Float[] wrap(float... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Float[0];
    }

    final Float[] array = new Float[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static float[] unWrap(Float... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new float[0];
    }

    final float[] array = new float[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], 0F);
    }
    return array;
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Double[] wrap(double... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Double[0];
    }

    final Double[] array = new Double[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static double[] unWrap(Double... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new double[0];
    }

    final double[] array = new double[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], 0D);
    }
    return array;
  }

  /**
   * 将原始类型数组包装为包装类型
   *
   * @param values 原始类型数组
   * @return 包装类型数组
   */
  public static Boolean[] wrap(boolean... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new Boolean[0];
    }

    final Boolean[] array = new Boolean[length];
    for (int i = 0; i < length; i++) {
      array[i] = values[i];
    }
    return array;
  }

  /**
   * 包装类数组转为原始类型数组
   *
   * @param values 包装类型数组
   * @return 原始类型数组
   */
  public static boolean[] unWrap(Boolean... values) {
    if (null == values) {
      return null;
    }
    final int length = values.length;
    if (0 == length) {
      return new boolean[0];
    }

    final boolean[] array = new boolean[length];
    for (int i = 0; i < length; i++) {
      array[i] = ObjectUtils.defaultIfNull(values[i], false);
    }
    return array;
  }

  public static void checkOffsetAndCount(long size, long offset, long byteCount) {
    if ((offset | byteCount) < 0 || offset > size || size - offset < byteCount) {
      throw new ArrayIndexOutOfBoundsException(
              String.format("size=%s offset=%s byteCount=%s", size, offset, byteCount));
    }
  }
}
